package org.infodavid.common.model.impl;

import java.beans.Transient;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.infodavid.common.model.IUser;
import org.infodavid.common.model.IUserSession;
import org.infodavid.common.model.impl.AbstractImprovedDataObjectImpl;
import org.joda.time.DateTime;

/**
 * The Class UserSessionImpl.
 */
public class UserSessionImpl extends AbstractImprovedDataObjectImpl<String> implements IUserSession {

	/** serialVersionUID. */
	private static final long serialVersionUID = -1478066595640761601L;

	/** The access count. */
	private long accessesCount;

	/** The authentication server. */
	private String authenticationServer;

	/** The authentication source. */
	private String authenticationSource;

	/** The last connection date. */
	private DateTime lastAccessDate;

	/** The last ip address. */
	private String lastIP;

	/** The user. */
	private IUser user;

	/** The properties. */
	private Map<String,String> properties;

	/** The flag describing if user has signed out. */
	private boolean signedOut = false;

	/**
	 * constructor.
	 * @throws Exception the exception
	 */
	protected UserSessionImpl() throws Exception {
		super();
	}

	/**
	 * constructor.
	 * @param keyArg the key
	 * @throws Exception the exception
	 */
	protected UserSessionImpl(final String keyArg) throws Exception {
		super();

		setKey(keyArg);
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.impl.DataObjectImpl#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}

		if (obj == null) {
			return false;
		}

		if (!(obj instanceof IUserSession)) {
			return false;
		}

		final IUserSession other = (IUserSession)obj;

		if (getKey() == null) {
			if (other.getKey() != null) {
				return false;
			}
		}
		else if (!getKey().equals(other.getKey())) {
			return false;
		}

		return true;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.listitems.IUserSessionListItem#getAccessesCount()
	 */
	public long getAccessesCount() {
		return accessesCount;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#getProperties()
	 */
	public Map<String,String> getProperties() {
		return properties;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#isSignedOut()
	 */
	public boolean isSignedOut() {
		return signedOut;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#getAuthenticationServer()
	 */
	public String getAuthenticationServer() {
		return authenticationServer;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#getAuthenticationSource()
	 */
	public String getAuthenticationSource() {
		return authenticationSource;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.listitems.IUserSessionListItem#getLastAccessDate()
	 */
	public DateTime getLastAccessDate() {
		return lastAccessDate;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.listitems.IUserSessionListItem#getLastIP()
	 */
	public String getLastIP() {
		return lastIP;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.listitems.IUserSessionListItem#getLoginName()
	 */
	@Transient
	public String getLoginName() {
		return getUser().getLoginName();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#getUser()
	 */
	public IUser getUser() {
		return user;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.impl.DataObjectImpl#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		final int result = 1;

		return prime * result + (getKey() == null ? 0 : getKey().hashCode());
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IBasicDataObject#init()
	 */
	@Override
	public void init() throws Exception {
		super.init();

		accessesCount = 0;
		lastAccessDate = null;
		lastIP = null;
		user = null;
		authenticationServer = null;
		authenticationSource = null;
		signedOut = false;
		properties = new HashMap<String,String>();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.listitems.IUserSessionListItem#setAccessesCount(long)
	 */
	@SuppressWarnings("boxing")
	public void setAccessesCount(final long value) {
		if (!equals(accessesCount, value)) {
			final Object old = accessesCount;
			accessesCount = value;
			markModified(ACCESSES_COUNT, old, accessesCount);
		}
	}

	/**
	 * Sets the properties.
	 * @param values the properties
	 */
	protected void setProperties(final Map<String,String> values) {
		final Object old = properties;
		properties = values;
		markModified(PROPERTIES, old, properties);
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#setSignedOut(boolean)
	 */
	@SuppressWarnings("boxing")
	public void setSignedOut(final boolean flag) {
		if (!equals(signedOut, flag)) {
			final Object old = signedOut;
			signedOut = flag;
			markModified(SIGNED_OUT, old, signedOut);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#setAuthenticationServer(java.lang.String)
	 */
	public void setAuthenticationServer(final String value) {
		if (!equals(authenticationServer, value)) {
			final Object old = authenticationServer;
			authenticationServer = value;
			markModified(AUTH_SERVER, old, authenticationServer);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#setAuthenticationSource(java.lang.String)
	 */
	public void setAuthenticationSource(final String value) {
		if (!equals(authenticationSource, value)) {
			final Object old = authenticationSource;
			authenticationSource = value;
			markModified(AUTH_SOURCE, old, authenticationSource);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.infodavid.common.model.listitems.IUserSessionListItem#setLastAccessDate(org.joda.time.DateTime
	 * )
	 */
	public void setLastAccessDate(final DateTime value) {
		if (!equals(lastAccessDate, value)) {
			final Object old = lastAccessDate;
			lastAccessDate = value;
			markModified(LAST_ACCESS_DATE, old, lastAccessDate);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.listitems.IUserSessionListItem#setLastIP(java.lang.String)
	 */
	public void setLastIP(final String value) {
		if (!equals(lastIP, value)) {
			final Object old = lastIP;
			lastIP = value;
			markModified(LAST_IP, old, lastIP);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.listitems.IUserSessionListItem#setLoginName(java.lang.String)
	 */
	public void setLoginName(final String value) {}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IUserSession#setUser(org.infodavid.common.model.IUser)
	 */
	public void setUser(final IUser value) {
		if (!equals(user, value)) {
			final Object old = user;
			user = value;
			markModified(USER, old, user);
		}
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#toString(java.lang.StringBuffer)
	 */
	@Override
	protected StringBuffer toString(final StringBuffer builder) {
		super.toString(builder);

		builder.append("[accessesCount=");
		builder.append(accessesCount);
		builder.append(", user=");

		if (user == null) {
			builder.append("null");
		}
		else {
			builder.append(user.getKey());
		}

		builder.append(", lastAccessDate=");
		builder.append(lastAccessDate);
		builder.append(", lastIP=");
		builder.append(lastIP);
		builder.append(", authenticationSource=");
		builder.append(authenticationSource);
		builder.append(", authenticationServer=");
		builder.append(authenticationServer);
		builder.append(", signedOut=");
		builder.append(signedOut);
		builder.append(", properties=");

		if (properties == null) {
			builder.append("null");
		}
		else {
			builder.append(Arrays.toString(properties.keySet().toArray()));
		}

		builder.append("]");

		return builder;
	}
}
